package com.grayscale.core.config;

import com.grayscale.core.constant.GrayScaleConstants;
import com.grayscale.core.util.GrayScaleOfflineUtil;
import com.grayscale.core.util.GrayScalePathBuilder;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.atomic.AtomicValue;
import org.apache.curator.framework.recipes.atomic.DistributedAtomicInteger;
import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.retry.RetryForever;
import org.apache.zookeeper.CreateMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @author liuli
 * 连接zk服务
 */
@Configuration
public class GrayScaleZookeeper {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    private  CuratorFramework zkClient;

    @Resource
    GrayScaleClientConfig grayScaleClientConfig;

    @Bean(initMethod = "start")
    public CuratorFramework curatorFramework(){
       log.info("zooKeeper client init...");
        //当zk连接时失败的重连策略
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(grayScaleClientConfig.getBaseSleepTime(), grayScaleClientConfig.getMaxRetries());
        zkClient =  CuratorFrameworkFactory.newClient(grayScaleClientConfig.getZkConnectUrl(),retryPolicy);
        return zkClient;
    }

    /***
     * 创建节点(临时)
     * @param path  路径
     * @throws Exception
     */
    public  void createTempNode(String path,String data) throws Exception {
        if (curatorFramework().checkExists().forPath(path) != null){
            //存在了  不创建， 更新数据
            setPathData(path, data);
            return ;
        }
        curatorFramework().create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path,data.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 创建节点(永久)
     * @param path
     * @param data
     * @param updateData  节点存在 是否更新数据
     * @throws Exception
     */
    public  void createPersistentNode(String path,String data,Boolean updateData) throws Exception {
        if (curatorFramework().checkExists().forPath(path) != null){
            //存在了  不创建， 更新数据
            if (updateData){
                setPathData(path, data);
            }
            return ;
        }
        curatorFramework().create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path,data.getBytes(StandardCharsets.UTF_8));
    }

    /***
     * 获取子节点列表
     * @param path
     * @return
     */
    public List<String>  getChildrenPath(String path){
        try {
            return curatorFramework().getChildren().forPath(path);
        } catch (Exception e) {
            log.error("获取子节点失败{}",e);
            return null;
        }
    }

    /***
     * 获取节点 数据
     * @param path
     * @return
     */
    public String getPathData(String path){
        try {
            byte[] data = curatorFramework().getData().forPath(path);
            if (data != null){
                return  new String(data,StandardCharsets.UTF_8);
            }
            return null;
        } catch (Exception e) {
            log.error("获取子节点失败{}",e);
            return null;
        }
    }
    /***
     * 设置节点 数据
     * @param path
     * @return
     */
    public Boolean setPathData(String path,String data){
        try {
            curatorFramework().setData().forPath(path,data.getBytes(StandardCharsets.UTF_8));
            return true;
        } catch (Exception e) {
            log.error("设置节点数据失败{}",e);
            return false;
        }
    }

    /***
     * 删除节点数据
     * @param path
     * @return
     */
    public Boolean delPathData(String path){
        try {
            curatorFramework().setData().forPath(path,null);
            return true;
        } catch (Exception e) {
            log.error("设置节点数据失败{}",e);
            return false;
        }
    }

    public void treeCacheListen(String hostDir) {
        log.info("开启:{} 节点的TreeCache监听",hostDir);
        try {
            TreeCache treeCache  =  new TreeCache(curatorFramework(), hostDir);
            treeCache.getListenable().addListener((c, event) -> {
                if ( event.getData() != null) {
                    String path =  event.getData().getPath();
                    byte[] data =  event.getData().getData();
                    String datStr = null;
                    if (data != null){
                        datStr = new String(data, StandardCharsets.UTF_8);
                    }
                    // 服务节点，参数节点，应用服务节点不处理（这些节点不记录 规则数据）,父节点不监听
                    if (path.endsWith(GrayScaleConstants.SERVER) || path.endsWith(GrayScaleConstants.PARAMETERS)
                            || path.contains(GrayScaleConstants.NODE)){
                        return;
                    }
                    //server 全局开关   [根节点]
                    if (path.equals(hostDir)){
                        GrayScaleOfflineUtil.writeDisk(GrayScalePathBuilder.buildOfflineServerSwitchPath(grayScaleClientConfig),datStr,true);
                    }else{
                    //方法 开关+规则   [叶子节点]
                        if (!path.contains("#")){
                            log.error("No processing required node:{}",path);
                            return;
                        }
                        if(path.endsWith(GrayScaleConstants.RULES)){
                            //方法参数
                            String function = path.replace(GrayScalePathBuilder.buildAppServerPath(grayScaleClientConfig.getAppName(),grayScaleClientConfig.getAppCode())+"/","").replace(GrayScaleConstants.RULES,"");
                            GrayScaleOfflineUtil.writeDisk(GrayScalePathBuilder.buildOfflineServerFunctionParametersPath(grayScaleClientConfig,function),datStr,true);
                        }
                        else{
                            //方法开关
                            String function = path.replace(GrayScalePathBuilder.buildAppServerPath(grayScaleClientConfig.getAppName(),grayScaleClientConfig.getAppCode())+"/","");
                            GrayScaleOfflineUtil.writeDisk(GrayScalePathBuilder.buildOfflineFunctionSwitchPath(grayScaleClientConfig,function),datStr,true);
                        }
                    }

                }
            });
            treeCache.start();
        } catch (Exception e) {
            log.error("TreeCache Listener Exception, path={} exception={}",hostDir,e.getMessage());
        }
    }

    /**
     * 创建计数器
     * @param path
     * @return
     */
    public Long counter(String path) {
        try {
            DistributedAtomicLong counter = new DistributedAtomicLong(curatorFramework(), path,new RetryForever(100));
            AtomicValue<Long> value  = counter.increment();
            return value.postValue();
        } catch (Exception e) {
            log.error("设置计数器失败{}",e);
        }
        return null;
    }

    /**
     * 获取计数器
     * @param path
     * @return
     */
    public Long getCounter(String path) {
        try {
            DistributedAtomicLong counter = new DistributedAtomicLong(curatorFramework(), path,new RetryForever(100));
            AtomicValue<Long> value  = counter.get();
            return value.postValue();
        } catch (Exception e) {
            log.error("获取计数器失败{}",e.getMessage(),e);
        }
        return null;
    }
}